//+------------------------------------------------------------------+
//|                        FileBin.mqh 二进制文件操作类头文件        |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
#include "File.h"  // 引入文件操作基类 CFile 的声明

//+------------------------------------------------------------------+
//| CFileBin 类                                                      |
//| 功能：MT5 二进制文件操作专用类，封装二进制文件的读写接口         |
//| 继承关系：public CFile（基于通用文件操作基类扩展二进制能力）      |
//| 核心特性：                                                      |
//|  1. 支持所有基础数据类型（char/short/int/long/float/double等）的二进制读写 |
//|  2. 支持数组、结构体、枚举、字符串及 CObject 派生对象的二进制序列化 |
//|  3. 自动以二进制模式打开文件，无需额外指定 FILE_BIN 标志          |
//+------------------------------------------------------------------+
class CFileBin : public CFile
  {
public:
   /**
    * @brief 构造函数：初始化二进制文件操作实例
    * @details 调用父类 CFile 构造函数，默认编码为 ANSI，未绑定文件
    */
                     CFileBin(void);

   /**
    * @brief 析构函数：销毁二进制文件操作实例
    * @details 自动调用父类 Close 方法，关闭已打开的二进制文件并释放资源
    */
                    ~CFileBin(void);

   //--- 二进制文件打开接口
   /**
    * @brief 以二进制模式打开文件（自动添加 FILE_BIN 标志）
    * @param file_name [in] 文件路径/名称（绝对路径或相对路径，如 "C:\\data.bin"）
    * @param open_flags [in] 打开模式标志（如 FILE_READ 只读、FILE_WRITE 写入、FILE_APPEND 追加，无需包含 FILE_BIN）
    * @return int - 操作结果：成功返回文件句柄（>0），失败返回 INVALID_HANDLE（-1）
    * @note 若已打开其他文件，会先自动关闭旧文件
    */
   int               Open(const string file_name,const int open_flags);

   //--- 二进制写入接口（基础数据类型）
   /**
    * @brief 写入 char/uchar 类型数据到二进制文件
    * @param value [in] 要写入的值（char 或 uchar 类型，自动适配无符号/有符号）
    * @return uint - 实际写入的字节数：成功返回 sizeof(char)（1字节），失败返回 0
    */
   uint              WriteChar(const char value);

   /**
    * @brief 写入 short/ushort 类型数据到二进制文件
    * @param value [in] 要写入的值（short 或 ushort 类型）
    * @return uint - 实际写入的字节数：成功返回 sizeof(short)（2字节），失败返回 0
    */
   uint              WriteShort(const short value);

   /**
    * @brief 写入 int/uint 类型数据到二进制文件
    * @param value [in] 要写入的值（int 或 uint 类型）
    * @return uint - 实际写入的字节数：成功返回 sizeof(int)（4字节），失败返回 0
    */
   uint              WriteInteger(const int value);

   /**
    * @brief 写入 long/ulong 类型数据到二进制文件
    * @param value [in] 要写入的值（long 或 ulong 类型）
    * @return uint - 实际写入的字节数：成功返回 sizeof(long)（8字节），失败返回 0
    */
   uint              WriteLong(const long value);

   /**
    * @brief 写入 float 类型数据到二进制文件
    * @param value [in] 要写入的单精度浮点数（4字节）
    * @return uint - 实际写入的字节数：成功返回 sizeof(float)（4字节），失败返回 0
    */
   uint              WriteFloat(const float value);

   /**
    * @brief 写入 double 类型数据到二进制文件
    * @param value [in] 要写入的双精度浮点数（8字节）
    * @return uint - 实际写入的字节数：成功返回 sizeof(double)（8字节），失败返回 0
    */
   uint              WriteDouble(const double value);

   //--- 二进制写入接口（字符串）
   /**
    * @brief 写入完整字符串到二进制文件（自动附加字符串长度）
    * @param value [in] 要写入的字符串（支持 Unicode/ANSI，由 SetUnicode 控制）
    * @return uint - 实际写入的字节数：成功返回 sizeof(int) + 字符串字节数，失败返回 0
    * @note 存储格式：先写入 4 字节字符串长度（int 类型），再写入字符串内容
    */
   uint              WriteString(const string value);

   /**
    * @brief 写入指定长度的字符串片段到二进制文件（不附加长度）
    * @param value [in] 要写入的字符串（超出长度部分会被截断）
    * @param size [in] 要写入的字符数（不是字节数，每个字符占 1/2 字节，取决于编码）
    * @return uint - 实际写入的字节数：成功返回 size * 字符字节数，失败返回 0
    */
   uint              WriteString(const string value,const int size);

   //--- 二进制写入接口（固定类型数组）
   /**
    * @brief 写入 char/uchar 数组到二进制文件
    * @param array [in] 要写入的数组（引用传递，需提前初始化）
    * @param start_item [in] 数组起始索引（从 0 开始，默认从第一个元素写入）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY，写入整个数组）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(char)，失败返回 0
    */
   uint              WriteCharArray(const char &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 写入 short/ushort 数组到二进制文件
    * @param array [in] 要写入的数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(short)，失败返回 0
    */
   uint              WriteShortArray(const short& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 写入 int/uint 数组到二进制文件
    * @param array [in] 要写入的数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(int)，失败返回 0
    */
   uint              WriteIntegerArray(const int& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 写入 long/ulong 数组到二进制文件
    * @param array [in] 要写入的数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(long)，失败返回 0
    */
   uint              WriteLongArray(const long &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 写入 float 数组到二进制文件
    * @param array [in] 要写入的数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(float)，失败返回 0
    */
   uint              WriteFloatArray(const float &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 写入 double 数组到二进制文件
    * @param array [in] 要写入的数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(double)，失败返回 0
    */
   uint              WriteDoubleArray(const double &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   //--- 二进制写入接口（通用模板，支持任意类型）
   /**
    * @brief 通用数组写入接口（模板函数，支持任意基础类型数组）
    * @tparam T 数组元素类型（如 int、double 等，需为 POD 类型）
    * @param array [in] 要写入的数组（引用传递）
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(T)，失败返回 0
    */
   template<typename T>
   uint              WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 写入结构体到二进制文件（模板函数，支持任意 POD 结构体）
    * @tparam T 结构体类型（需为 POD 类型，不含指针、动态数组等复杂成员）
    * @param data [in] 要写入的结构体（引用传递，需提前初始化成员）
    * @return uint - 实际写入的字节数：成功返回 sizeof(T)，失败返回 0
    */
   template<typename T>
   uint              WriteStruct(T &data);

   /**
    * @brief 写入 CObject 派生对象到二进制文件（调用对象的 Save 方法）
    * @param object [in] 要写入的对象指针（需继承自 CObject，且实现 Save 方法）
    * @return bool - 操作结果：true 表示写入成功，false 表示失败（对象为空或 Save 失败）
    */
   bool              WriteObject(CObject *object);

   /**
    * @brief 写入枚举类型到二进制文件（自动转换为 int 存储）
    * @tparam T 枚举类型
    * @param value [in] 要写入的枚举值
    * @return uint - 实际写入的字节数：成功返回 sizeof(int)（4字节），失败返回 0
    */
   template<typename T>
   uint              WriteEnum(const T value) { return(WriteInteger((int)value)); }

   //--- 二进制读取接口（基础数据类型）
   /**
    * @brief 从二进制文件读取 char/uchar 类型数据
    * @param value [out] 读取结果存储变量（引用传递，接收 char/uchar 类型值）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（文件结束或句柄无效）
    */
   bool              ReadChar(char &value);

   /**
    * @brief 从二进制文件读取 short/ushort 类型数据
    * @param value [out] 读取结果存储变量（引用传递）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    */
   bool              ReadShort(short &value);

   /**
    * @brief 从二进制文件读取 int/uint 类型数据
    * @param value [out] 读取结果存储变量（引用传递）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    */
   bool              ReadInteger(int &value);

   /**
    * @brief 从二进制文件读取 long/ulong 类型数据
    * @param value [out] 读取结果存储变量（引用传递）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    */
   bool              ReadLong(long &value);

   /**
    * @brief 从二进制文件读取 float 类型数据
    * @param value [out] 读取结果存储变量（引用传递，接收单精度浮点数）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    */
   bool              ReadFloat(float &value);

   /**
    * @brief 从二进制文件读取 double 类型数据
    * @param value [out] 读取结果存储变量（引用传递，接收双精度浮点数）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    */
   bool              ReadDouble(double &value);

   //--- 二进制读取接口（字符串）
   /**
    * @brief 从二进制文件读取完整字符串（先读长度，再读内容）
    * @param value [out] 读取结果存储变量（引用传递，接收完整字符串）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（长度读取失败或内容不完整）
    * @note 需与 WriteString(const string value) 配对使用，读取格式为“4字节长度 + 字符串内容”
    */
   bool              ReadString(string &value);

   /**
    * @brief 从二进制文件读取指定长度的字符串片段
    * @param value [out] 读取结果存储变量（引用传递，接收字符串片段）
    * @param size [in] 要读取的字符数（不是字节数，取决于编码）
    * @return bool - 操作结果：true 表示读取成功（实际字符数等于 size），false 表示失败
    * @note 需与 WriteString(const string value, const int size) 配对使用
    */
   bool              ReadString(string &value,const int size);

   //--- 二进制读取接口（固定类型数组）
   /**
    * @brief 从二进制文件读取 char/uchar 数组
    * @param array [out] 读取结果存储数组（引用传递，需提前分配足够空间）
    * @param start_item [in] 数组起始索引（默认 0，从第一个元素开始存储）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY，需确保数组空间足够）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(char)，失败返回 0
    */
   uint              ReadCharArray(char &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 从二进制文件读取 short/ushort 数组
    * @param array [out] 读取结果存储数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(short)，失败返回 0
    */
   uint              ReadShortArray(short& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 从二进制文件读取 int/uint 数组
    * @param array [out] 读取结果存储数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(int)，失败返回 0
    */
   uint              ReadIntegerArray(int& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 从二进制文件读取 long/ulong 数组
    * @param array [out] 读取结果存储数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(long)，失败返回 0
    */
   uint              ReadLongArray(long &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 从二进制文件读取 float 数组
    * @param array [out] 读取结果存储数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(float)，失败返回 0
    */
   uint              ReadFloatArray(float &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 从二进制文件读取 double 数组
    * @param array [out] 读取结果存储数组
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(double)，失败返回 0
    */
   uint              ReadDoubleArray(double &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   //--- 二进制读取接口（通用模板，支持任意类型）
   /**
    * @brief 通用数组读取接口（模板函数，支持任意基础类型数组）
    * @tparam T 数组元素类型（如 int、double 等 POD 类型）
    * @param array [out] 读取结果存储数组（引用传递，需提前分配足够空间）
    * @param start_item [in] 数组起始索引（默认 0）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(T)，失败返回 0
    */
   template<typename T>
   uint              ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 从二进制文件读取结构体（模板函数，支持任意 POD 结构体）
    * @tparam T 结构体类型（需为 POD 类型，不含指针、动态数组等复杂成员）
    * @param data [out] 读取结果存储结构体（引用传递，接收完整结构体数据）
    * @return uint - 实际读取的字节数：成功返回 sizeof(T)，失败返回 0
    */
   template<typename T>
   uint              ReadStruct(T &data);

   /**
    * @brief 从二进制文件读取 CObject 派生对象（调用对象的 Load 方法）
    * @param object [in/out] 要读取的对象指针（需提前创建实例，调用其 Load 方法恢复数据）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（对象为空或 Load 失败）
    */
   bool              ReadObject(CObject *object);

   /**
    * @brief 从二进制文件读取枚举类型（从 int 转换为枚举）
    * @tparam T 枚举类型
    * @param value [out] 读取结果存储变量（引用传递，接收枚举值）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（int 读取失败或类型不匹配）
    */
   template<typename T>
   bool              ReadEnum(T &value);
  };
//+------------------------------------------------------------------+